﻿using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using System.Xml.Linq;

namespace FCRE.helper
{
    static class FileUtils
    {
        public static bool IsDir(this string path)
        {
            return File.GetAttributes(path).HasFlag(FileAttributes.Directory);
        }

        public static string NormalizePath(string path)
        {
            return Path.GetFullPath(new Uri(path).LocalPath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).ToUpperInvariant();
        }

        public static XElement LoadFileAsXml(this string filePath)
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                throw new ArgumentNullException("filePath");
            }
            if (!File.Exists(filePath))
            {
                throw new ArgumentNullException(string.Format("Cannot find file with path '{0}'",filePath));
            }
            using (StreamReader textReader = File.OpenText(filePath))
            {
                return XElement.Load(textReader);
            }
        }

        public static FileSystemInfo GetFileSystemInfo(string path)
        {
            if (File.Exists(path))
            {
                return new FileInfo(path);
            }
            if (Directory.Exists(path))
            {
                return new DirectoryInfo(path);
            }
            return null;
        }

        public static string ToValidFileName(string s)
        {
            return ToValidFileName(s, string.Empty, null);
        }

        public static string ToValidFileName(string s, string invalidReplacement)
        {
            return ToValidFileName(s, invalidReplacement, null);
        }

        public static string ToValidFileName(string s, string invalidReplacement, string spaceReplacement)
        {
            StringBuilder stringBuilder = new StringBuilder(s);
            char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
            foreach (char c in invalidFileNameChars)
            {
                if (invalidReplacement != null)
                {
                    stringBuilder.Replace(c.ToString(), invalidReplacement);
                }
            }
            if (spaceReplacement != null)
            {
                stringBuilder.Replace(" ", spaceReplacement);
            }
            return stringBuilder.ToString();
        }

        public static string MapPath(string path)
        {
            if (Path.IsPathRooted(path))
            {
                return path;
            }
            if (HostingEnvironment.IsHosted)
            {
                return HostingEnvironment.MapPath(path);
            }
            if (VirtualPathUtility.IsAppRelative(path))
            {
                string text = VirtualPathUtility.ToAbsolute(path, "/");
                text = text.Replace('/', '\\');
                text = text.Substring(1);
                return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, text);
            }
            throw new Exception(string.Format("Could not resolve non-rooted path: {0}", path));//CultureInfo.InvariantCulture
        }

        public static void EnsureFileMoved(string sourceFileName, string destFileName)
        {
            if (File.Exists(sourceFileName))
            {
                EnsureFileDeleted(destFileName);
                File.Move(sourceFileName, destFileName);
            }
        }

        public static void EnsureFileDeleted(string path, int retryTimes = 1)
        {
            for (int i = 1; i <= retryTimes; i++)
            {
                try
                {
                    if (File.Exists(path))
                    {
                        File.SetAttributes(path, FileAttributes.Normal);
                        File.Delete(path);
                    }
                    return;
                }
                catch (Exception ex)
                {
                    if (i == retryTimes)
                    {
                        throw ex;
                    }
                    Thread.Sleep(50);
                }
            }
        }

        public static void EnsureDirectoryDeleted(string path, bool ignoreError = false)
        {
            try
            {
                if (Directory.Exists(path))
                {
                    DirectoryInfo directoryInfo = new DirectoryInfo(path)
                    {
                        Attributes = FileAttributes.Normal
                    };
                    FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos("*", SearchOption.AllDirectories);
                    foreach (FileSystemInfo fileSystemInfo in fileSystemInfos)
                    {
                        if ((fileSystemInfo.Attributes & FileAttributes.ReadOnly) > (FileAttributes)0)
                        {
                            fileSystemInfo.Attributes = FileAttributes.Normal;
                        }
                    }
                    directoryInfo.Delete(true);
                }
            }
            catch (Exception ex)
            {
                if (!ignoreError)
                {
                    throw ex;
                }
            }
        }

        public static void EnsureDirectoryDeleted(string path, int retryTimes)
        {
            for (int i = 1; i <= retryTimes; i++)
            {
                try
                {
                    if (Directory.Exists(path))
                    {
                        DirectoryInfo directoryInfo = new DirectoryInfo(path)
                        {
                            Attributes = FileAttributes.Normal
                        };
                        FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos("*", SearchOption.AllDirectories);
                        foreach (FileSystemInfo fileSystemInfo in fileSystemInfos)
                        {
                            if ((fileSystemInfo.Attributes & FileAttributes.ReadOnly) > (FileAttributes)0)
                            {
                                fileSystemInfo.Attributes = FileAttributes.Normal;
                            }
                        }
                        directoryInfo.Delete(true);
                    }
                    return;
                }
                catch (Exception ex)
                {
                    if (i == retryTimes)
                    {
                        throw ex;
                    }
                    Thread.Sleep(10);
                }
            }
        }

        public static void EnsureDirectoryEmpty(string path, bool ignoreError = false)
        {
            try
            {
                if (Directory.Exists(path))
                {
                    DirectoryInfo directoryInfo = new DirectoryInfo(path);
                    FileInfo[] files = directoryInfo.GetFiles("*", SearchOption.AllDirectories);
                    foreach (FileInfo fileInfo in files)
                    {
                        if ((fileInfo.Attributes & FileAttributes.ReadOnly) > (FileAttributes)0)
                        {
                            fileInfo.Attributes = FileAttributes.Normal;
                        }
                        fileInfo.Delete();
                    }
                    DirectoryInfo[] directories = directoryInfo.GetDirectories();
                    foreach (DirectoryInfo directoryInfo2 in directories)
                    {
                        if ((directoryInfo2.Attributes & FileAttributes.ReadOnly) > (FileAttributes)0)
                        {
                            directoryInfo2.Attributes = FileAttributes.Normal;
                        }
                        directoryInfo2.Delete(true);
                    }
                }
            }
            catch (Exception ex)
            {
                if (!ignoreError)
                {
                    throw ex;
                }
            }
        }

        public static void EnsureDirectoryEmpty(string path, int retryTimes)
        {
            for (int i = 1; i <= retryTimes; i++)
            {
                try
                {
                    if (Directory.Exists(path))
                    {
                        DirectoryInfo directoryInfo = new DirectoryInfo(path);
                        FileInfo[] files = directoryInfo.GetFiles("*", SearchOption.AllDirectories);
                        foreach (FileInfo fileInfo in files)
                        {
                            if ((fileInfo.Attributes & FileAttributes.ReadOnly) > (FileAttributes)0)
                            {
                                fileInfo.Attributes = FileAttributes.Normal;
                            }
                            fileInfo.Delete();
                        }
                        DirectoryInfo[] directories = directoryInfo.GetDirectories();
                        foreach (DirectoryInfo directoryInfo2 in directories)
                        {
                            if ((directoryInfo2.Attributes & FileAttributes.ReadOnly) > (FileAttributes)0)
                            {
                                directoryInfo2.Attributes = FileAttributes.Normal;
                            }
                            directoryInfo2.Delete(true);
                        }
                    }
                    return;
                }
                catch (Exception ex)
                {
                    if (i == retryTimes)
                    {
                        throw ex;
                    }
                    Thread.Sleep(10);
                }
            }
        }

        public static void EnsureFileExists(string path, int retryTimes = 1)
        {
            for (int i = 1; i <= retryTimes; i++)
            {
                try
                {
                    if (!File.Exists(path))
                    {
                        using (File.Create(path))
                        {
                        }
                    }
                    return;
                }
                catch (Exception ex)
                {
                    if (i == retryTimes)
                    {
                        throw ex;
                    }
                    Thread.Sleep(50);
                }
            }
        }

        public static FileStream EnsureFileCreate(string path, int retryTimes = 1)
        {
            for (int i = 1; i <= retryTimes; i++)
            {
                try
                {
                    return File.Create(path);
                }
                catch (Exception ex)
                {
                    if (i == retryTimes)
                    {
                        throw ex;
                    }
                    Thread.Sleep(50);
                }
            }
            return null;
        }

        public static void EnsureDirectoryExists(string path, int retryTimes = 1)
        {
            for (int i = 1; i <= retryTimes; i++)
            {
                try
                {
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    return;
                }
                catch (Exception ex)
                {
                    if (i == retryTimes)
                    {
                        throw ex;
                    }
                    Thread.Sleep(50);
                }
            }
        }

        public static void MoveDirectoryContents(string sourceDir, string destDir, bool overwrite = true)
        {
            string[] directories = Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories);
            for (int i = 0; i < directories.Length; i++)
            {
                Directory.CreateDirectory(directories[i].Replace(sourceDir, destDir));
            }
            directories = Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories);
            foreach (string text in directories)
            {
                string text2 = text.Replace(sourceDir, destDir);
                if (File.Exists(text2))
                {
                    if (!overwrite)
                    {
                        continue;
                    }
                    EnsureFileDeleted(text2);
                }
                File.Move(text, text2);
            }
        }

        public static void CopyDirectoryContents(string sourceDir, string destDir, bool overwrite = true)
        {
            string[] directories = Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories);
            for (int i = 0; i < directories.Length; i++)
            {
                Directory.CreateDirectory(directories[i].Replace(sourceDir, destDir));
            }
            directories = Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories);
            foreach (string obj in directories)
            {
                string destFileName = obj.Replace(sourceDir, destDir);
                File.Copy(obj, destFileName, overwrite);
            }
        }

        public static byte[] ReadAllBytesShareWrite(string path)
        {
            using (FileStream fileStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                int num = Convert.ToInt32(fileStream.Length);
                byte[] array = new byte[num];
                fileStream.Read(array, 0, num);
                return array;
            }
        }

        public static void WriteByteToFile(byte[] fReadByte, string path)
        {
            using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate))
            {
                fileStream.Write(fReadByte, 0, fReadByte.Length);
            }
        }

        public static void Copy(Stream source, Stream destination, byte[] buffer)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (destination == null)
            {
                throw new ArgumentNullException("destination");
            }
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (buffer.Length < 128)
            {
                throw new ArgumentException("Buffer is too small", "buffer");
            }
            bool flag = true;
            while (flag)
            {
                int num = source.Read(buffer, 0, buffer.Length);
                if (num > 0)
                {
                    destination.Write(buffer, 0, num);
                    continue;
                }
                destination.Flush();
                flag = false;
            }
        }
        /// <summary>
        /// 压缩成rar文件
        /// </summary>
        /// <param name="destFileName"></param>
        /// <param name="srcFilesName"></param>
        /// <param name="exceptFile"></param>
        public static void File2Rar(string destFileName, string srcFilesName, string exceptFile = null)
        {
            using (Process unrar = new Process())
            {
                unrar.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"rar.exe";
                string argStr = " a -ep1 -pucte2015 ";
                if (exceptFile != null) argStr += " -x" + exceptFile + " ";
                argStr += destFileName + " ";
                argStr += srcFilesName;
                unrar.StartInfo.Arguments = argStr;
                unrar.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;//隐藏rar本身的窗口
                unrar.Start();
                unrar.WaitForExit();//等待压缩完成
                unrar.Close();
            }
        }
        /// <summary>
        /// 解压rar文件
        /// </summary>
        /// <param name="destDirName"></param>
        /// <param name="srcFilesName"></param>
        public static void Rar2File(string destDirName, string srcFilesName)
        {
            using (Process unrar = new Process())
            {
                unrar.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"rar.exe";
                string argStr = " x -o- -y -pucte2015 ";
                argStr += srcFilesName + " ";
                argStr += destDirName;
                unrar.StartInfo.Arguments = argStr;
                unrar.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;//隐藏rar本身的窗口
                unrar.Start();
                unrar.WaitForExit();//等待压缩完成
                unrar.Close();
            }
        }
    }
}
